设计模式之禅
[TOC]
第二部分 23种设计模式- 结构类模式
结构类模式: 描述类和对象之间如何进行有效的组织,以形成良好的软件体系结构
一.适配器模式
1.定义
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法再一起工作的两个类能够在一起工作
适配器模式又叫变压器模式
2.类图
类适配器
对象适配器(使用的场景相对较多)
3.角色
Target目标角色 — 接口
该角色定义把其他类转换为何种接口,也就是我们的期望接口Adaptee源角色
它是已经存在的,运行良好的类或对象- Adapter适配器对象
适配器模式的核心角色,其他两个角色都是已经存在的角色。适配器角色需要新建立,用于把源角色转换成目标角色,通过继承或类关联的方式
4.优点
- 增加类的透明性
- 提高类的复用度
- 灵活性非常好
5.注意事项
适配器模式在详细设计阶段不要考虑它,它不是为了解决还处在开发阶段的问题
二.代理模式(委托模式)
1.定义
为其他对象提供一种代理以控制对这个对象的访问
2.类图
3.角色
Subject 抽象主题角色
抽象主题类可以是抽象类也可以是接口。(包含需要被代理的方法)RealSubject 具体主题角色
委托角色,被代理角色,业务逻辑的具体执行者Proxy 代理主题角色
代理类。它负责对真实角色的应用,在真实角色处理完毕前后做预处理和善后处理工作
4.扩展
- *1.普通代理
我们需要知道代理类的存在。需要自己new - *2.强制代理
调用者直接调用真实角色,而不用关心代理是否存在,代理从真实角色中产生 - *3.虚拟代理
在需要的时候才初始化主题对象,可以避免被代理对象较多而引起的初始化缓慢问题。缺点是需要在每个方法中判断主题对象是否被创建 - *4.动态代理 — 类图
三.装饰模式
1.定义
动态地给一个对象添加一些额外的职责,就增加功能
2.类图
3.角色
Component 抽象构件
一个接口或抽象类,原始对象。放需要加强的方法ConcreteComponent具体构件
原始的接口或抽象类的实现Decorator 装饰角色
聚合原始构件,实现接口或抽象方法,加以功能
4.应用
优点: 装饰类和被装饰类可以独立发展,不会互相耦合。动态扩展一个实现类的功能
缺点: 多层装饰会比较复杂
装饰器模式、代理模式比较
- 装饰者模式:可以让使用者直观的看到增强了哪些功能。装饰者能够在运行时递归地被构造
- 代理模式:限制了使用者,只去调用代理,至于代理里面增加了什么功能,使用者是不知道,隐藏了一个对象的具体信息。代理和真实对象之间的的关系通常在编译时就已经确定
四.组合模式
1.定义
将对象组合成树形结构表示”部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
2.类图
3.角色
Component 抽象构件角色
定义组合对象的共有方法和属性,可以定义一些默认的行为或属性Leaf 叶子构件
叶子对象,其下再没有其他分支,即遍历的最小单元Composite 树枝构件
树枝对象,组合树枝节点和叶子节点形成一个树形结构
遍历树结构,参考代码
组合模式是对依赖倒置原则的破坏。
4.应用
优点: 高层模块调用简单、节点自由增加
缺点: 直接使用了实现类,在面向接口编程上是很不恰当的,与依赖倒置原则冲突
使用场景: 维护和展示部分-整体关系、从一个整体中能够独立出部分模块或功能的场景
5.扩展
在实际项目中,树的组装信息是存储在关系型数据库中。我们从数据库读取出来,展示
- 5.1.安全模式
类图
Component表示结点,区分叶子对象和树枝对象。不提供客户端不可能调用到的方法。但不够透明,因为叶子构件和容器构件具有不同的方法,必须有区别地对待叶子构件和容器构件。违反依赖倒置原则
- 5.2.透明模式
类图
在该模式中不区分叶子、树枝对象。确保所有的构件类都有相同的接口,客户端可以相同地对待所有的对象。符合依赖倒置原则。但不够安全,因为叶子对象和容器对象在本质上是有区别的。提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)
五.门面模式(外观模式)
1. 定义
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行
2. 类图
3. 角色
- Facade 门面角色
客户端呢可以调用这个角色的方法,该角色知道子系统的所有功能与职责 - Subsystem 子系统角色
4. 应用
优点: 减少系统的相互依赖、提高灵活性安全性
缺点: 不符合开闭原则,发现错误后需要去修改门面角色的代码
- 一个子系统可以有多个门面
- 门面不参与子系统内的业务逻辑
六.享元模式
1. 定义
使用共享对象有效地支持大量的细粒度的对象
2. 类图
3. 角色
外部状态: 该状态随环境改变而改变,是不可以共享的状态。对象得以依赖的一个标记
内部状态: 该状态不随环境改变而改变,存储在享元对象内部,对象可共享出来的信息
Flyweight 抽象享元角色
同时定义出对象的外部状态和内部状态ConcreteFlyweight 具体享元角色
具体的一个产品类,实现抽象角色定义。确定好内部状态(共享),外部状态可供改变不能出现一个操作改变内部状态,同时改变外部状态
- unsharedConcreteFlyweight 不可共享的享元角色
不存在外部状态、有安全要求不能使用共享技术的对象。该对象一般不会出现在享元工厂中
使用抽象享元角色的属性,但不是共享对象
- FlyweightFactory 享元工厂
构造一个池容器,提供从池中获得对象的方法
在程序开发中,确认只需要一次赋值的属性则设置为final类型,避免无意修改导致逻辑混乱
4. 应用优点
大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能
缺点
提高了系统复杂性,需要分离出外部状态和内部状态,且外部状态具有固化性,不随内部状态改变而改变,否则会导致系统的逻辑混乱
使用场景
- 系统中存在大量的相似对象
- 需要缓冲池的场景
5. 扩展
- 线程安全问题
七.桥梁模式
1.定义
将抽象和实现解耦,使得两者可以独立地变化
2.类图
3.角色
- Abstraction 抽象化角色
主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类 - Implementor 实现化角色
接口或者抽象类,定义角色必须的行为和属性 - RefinedAbstraction 修正抽象化角色
引用实现化角色对抽象化角色进行修正 - ConcreteImplementor 具体实现化角色
实现接口或抽象类定义的方法和属性
类似于聚合、合成的一种模式
4.应用优点
- 抽象和实现分离
- 优秀的扩充能力
- 实现细节对客户透明
使用场景
- 不希望或不使用继承的场景
- 接口或抽象类不稳定的场景
- 重用性要求较高的场景